﻿/****************************************************************************
** file: yuv2rgb.h
** brief: 提供了 YUV 格式的图像数据与 RGB 格式的图像数据的相互转换功能。
** Copyright (C) LiYuan
** Author: LiYuan
** E-Mail: 18069211#qq(.)com
** Version 1.0.1
** Last modified: 2019.01.11
** Modified By: LiYuan
****************************************************************************/

#ifndef YUV2RGBCONVERTER_H
#define YUV2RGBCONVERTER_H

#include <stdint.h>
#include <QColor>

/**
 * @brief yuv2rgb  yuv 转 RGB，采用公式法，计算速度较慢
 * @param y [0, 255]
 * @param u [0, 255]
 * @param v [0, 255]
 * @return
 */
inline QRgb yuv2rgb(uint8_t y, uint8_t u, uint8_t v)
{
    int R = qRound(y + 1.403 * (v - 128)); // 四舍五入到最近的整数
    int G = qRound( - 0.343 * (u - 128) - 0.714 * (v - 128));
    int B = qRound(y + 1.770 * (u - 128));

    R = qBound(0, R, 255);
    G = qBound(0, y + G, 255);
    B = qBound(0, B, 255);

    return qRgb(R, G, B);
}

/**
 * @brief rgb2yuv RGB 转 YUV，速度较慢，但是似乎也没有特别快的算法。
 * @param rgb [0, 255]
 * @param y [0, 255]
 * @param u [0, 255]
 * @param v [0, 255]
 */
inline void rgb2yuv(QRgb rgb, uint8_t &y, uint8_t &u, uint8_t &v)
{
    int R = qRed(rgb);
    int B = qBlue(rgb);
    int G = qGreen(rgb);

    int Y, U, V;
    Y = 0.299 * R + 0.587 * G + 0.114 * B;
    U = -0.169 * R - 0.331 * G + 0.500 * B + 127;
    V = 0.500 * R - 0.419 * G - 0.081 * B + 127;

    y = qBound(0, Y, 255);
    u = qBound(0, U, 255);
    v = qBound(0, V, 255);
}

/**
 * @brief yuv2rgb_fast ，采用了整型运算，速度较快，可以用于实时应用。
 * @param y [0, 255]
 * @param u [0, 255]
 * @param v [0, 255]
 * @return
 */
inline QRgb yuv2rgb32_fast(uint8_t y, uint8_t u, uint8_t v)
{
    u = u - 128;
    v = v - 128;

    int r_dif = v + ((v * 103) >> 8);
    int g_dif = -((u * 88) >> 8) - ((v * 183) >> 8);
    int b_dif = u +((u * 198) >> 8);

    int R = y + r_dif;
    int G = y + g_dif;
    int B = y + b_dif;

    R = qBound(0, R, 255);
    G = qBound(0, G, 255);
    B = qBound(0, B, 255);

    return qRgb(R, G, B);
}

class YUV2RGBConverter
{
public:
    YUV2RGBConverter(); 
    /**
     * @brief yuv2rgb 将 YUV 转化为 RGB
     * @param y [0, 255]
     * @param u [0, 255]
     * @param v [0, 255]
     * @return
     */
    uint32_t YUV_to_RGB32(uint8_t y, uint8_t u, uint8_t v);
    uint32_t YUV_to_BGR32(uint8_t y, uint8_t u, uint8_t v);

    void YUV_to_RGB24(uint8_t y, uint8_t u, uint8_t v, uint8_t * rgb24);
    void YUV_to_BGR24(uint8_t y, uint8_t u, uint8_t v, uint8_t * bgr24);
    /**
     * @brief yuy2_to_rgb32 yuy2 格式转换为 RGB32，一次转换一行
     * @param yuy2 yuyvyuyv... 方式排列的数据
     * @param rgb [out]
     * @param size 像素个数（与 y 的数量相同）
     */
    void YUY2_to_RGB32(const uint8_t * yuy2, uint32_t * rgb32, size_t size);
    void YUYV_to_RGB32(const uint8_t * yuyv, uint32_t * rgb32, size_t size) {YUY2_to_RGB32(yuyv, rgb32, size);}

    void YUYV_to_BGR32(const uint8_t * yuyv, uint32_t * bgr32, size_t size);
    void YUY2_to_BGR32(const uint8_t * yuy2, uint32_t * bgr32, size_t size){YUYV_to_BGR32(yuy2, bgr32, size);}
    /**
     * @brief yuy2_to_rgb24 yuy2 格式转换为 RGB24，一次转换一行
     * @param yuy2 yuyvyuyv... 方式排列的数据
     * @param rgb24 [out] 排列顺序时 BGR BGR BGR...
     * @param size 像素个数
     */
    void YUY2_to_RGB24(const uint8_t * yuy2, uint8_t * rgb24, size_t size);
    void YUYV_to_RGB24(const uint8_t * yuyv, uint8_t * rgb24, size_t size) {YUY2_to_RGB24(yuyv, rgb24, size);}
    /**
     * @brief vyuy_to_rgb32 vyuy 格式转换为 RGB32，一次转换一行
     * @param vyuy vyuyvyuyvyuyv... 方式排列的数据
     * @param rgb32 [out]
     * @param size 像素个数（与 y 的数量相同）
     */
    void VYUY_to_RGB32(const uint8_t * vyuy, uint32_t * rgb32, size_t size);
    void VYUY_to_BGR32(const uint8_t * vyuy, uint32_t * bgr32, size_t size);
    void UYVY_to_RGB32(const uint8_t * uyvy, uint32_t * rgb32, size_t size);
    void UYVY_to_BGR32(const uint8_t * uyvy, uint32_t * bgr32, size_t size);
    /**
     * @brief vyuy_to_rgb24 vyuy 格式转换为 RGB24，一次转换一行
     * @param vyuy vyuyvyuyvyuyv... 方式排列的数据
     * @param rgb24 [out] 排列方式 BGR BGR BGR...
     * @param size size 像素个数（与 y 的数量相同）
     */
    void VYUY_to_RGB24(const uint8_t * vyuy, uint8_t * rgb24, size_t size);
    void UYVY_to_RGB24(const uint8_t * uyvy, uint8_t * rgb24, size_t size);
    void VYUY_to_BGR24(const uint8_t * vyuy, uint8_t * bgr24, size_t size);
    void UYVY_to_BGR24(const uint8_t * uyvy, uint8_t * bgr24, size_t size);
    /**
     * @brief yuv422 yuv422 格式转换为 RGB32，一次转换一行
     * @param yuv_y y 分量的数组，共有 size 个元素
     * @param yuv_u u 分量的数组，有 size / 2 个元素
     * @param yuv_v v 分量的数组，有 size / 2 个元素
     * @param rgb32 [out]
     * @param size 像素个数（与 y 的数量相同）
     */
    void YUV422_to_RGB32(const uint8_t * yuv_y,
                const uint8_t * yuv_u,
                const uint8_t * yuv_v,
                uint32_t * rgb32,
                size_t size);
    void YUV422_to_BGR32(const uint8_t * yuv_y,
                const uint8_t * yuv_u,
                const uint8_t * yuv_v,
                uint32_t * bgr32,
                size_t size);
    /**
     * @brief yuv422_to_rgb24 yuv422 格式转换为 RGB24，一次转换一行
     * @param yuv_y
     * @param yuv_u
     * @param yuv_v
     * @param rgb24 [out] 排列方式为 BGR BGR BGR..
     * @param size
     */
    void YUV422_to_RGB24(const uint8_t * yuv_y,
                const uint8_t * yuv_u,
                const uint8_t * yuv_v,
                uint8_t * rgb24,
                size_t size);
    void YUV422_to_BGR24(const uint8_t * yuv_y,
                const uint8_t * yuv_u,
                const uint8_t * yuv_v,
                uint8_t * bgr24,
                size_t size);
private:
    static uint8_t RYV[256][256];
    static uint8_t BYU[256][256];
    static uint16_t TUV[256][256];
    static uint8_t GYT[256][270];
    static bool m_table_init;
};

inline QRgb YUV2RGBConverter::YUV_to_RGB32(uint8_t y, uint8_t u, uint8_t v)
{
    int R = RYV[y][v];
    int G = GYT[y][TUV[u][v]];
    int B = BYU[y][u];
    return qRgb(R, G, B);
}

inline uint32_t YUV2RGBConverter::YUV_to_BGR32(uint8_t y, uint8_t u, uint8_t v)
{
    uint32_t ret; //0xBBGGRRff
    uint8_t *p = (uint8_t *) & ret;

    int R = RYV[y][v];
    int G = GYT[y][TUV[u][v]];
    int B = BYU[y][u];

    p[0] = 0xff;
    p[1] = R;
    p[2] = G;
    p[3] = B;
    return ret;
}

///rgb24 中像素排列顺序时 BGRBGRBGRBGR...
inline void YUV2RGBConverter::YUV_to_RGB24(uint8_t y, uint8_t u, uint8_t v, uint8_t * rgb24)
{
    rgb24[0] = BYU[y][u];
    rgb24[1] = GYT[y][TUV[u][v]];
    rgb24[2] = RYV[y][v];
}

inline void YUV2RGBConverter::YUV_to_BGR24(uint8_t y, uint8_t u, uint8_t v, uint8_t * bgr24)
{
    bgr24[2] = BYU[y][u];
    bgr24[1] = GYT[y][TUV[u][v]];
    bgr24[0] = RYV[y][v];
}

#endif // YUV2RGBCONVERTER_H
